package com.zufangbao.earth.email;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import com.demo2do.core.persistence.support.Filter;
import com.demo2do.core.utils.DateUtils;
import com.zufangbao.earth.email.excel.ExcelFinanceHandler;
import com.zufangbao.earth.email.excel.ExcelOverDueOrderExcelHandler;
import com.zufangbao.earth.email.excel.ExcelUpcomingOrderHandler;
import com.zufangbao.earth.handler.impl.MailSenderHandler;
import com.zufangbao.sun.entity.finance.FinancePaymentRecord;
import com.zufangbao.sun.entity.finance.FinanceReportTitles;
import com.zufangbao.sun.entity.finance.ReportDataGenerator;
import com.zufangbao.sun.entity.icbc.business.ReceiveOrderMap;
import com.zufangbao.sun.entity.order.Order;
import com.zufangbao.sun.entity.order.OrderStatus;
import com.zufangbao.sun.entity.order.OverDueReportTitles;
import com.zufangbao.sun.entity.order.RepaymentType;
import com.zufangbao.sun.entity.order.TransactionRecordLog;
import com.zufangbao.sun.entity.order.TransactionRecordOperateStatus;
import com.zufangbao.sun.entity.order.TransactionRecordStatus;
import com.zufangbao.sun.entity.order.UpcomingReportTitles;
import com.zufangbao.sun.service.AppArriveRecordService;
import com.zufangbao.sun.service.FinancePaymentRecordService;
import com.zufangbao.sun.service.OrderService;
import com.zufangbao.sun.service.ReceiveOrderMapService;
import com.zufangbao.sun.service.TransactionRecordLogService;

@Service("emailSender")
public class GenerateEmailOrExcelDataHandler {
	@Resource
	private MailSenderHandler mailSenderHandler;
	@Resource
	private FreeMarkerConfigurer freeMarkerConfigurer;
	@Resource
	private ExcelFinanceHandler excelFinanceService;
	@Resource
	private ExcelOverDueOrderExcelHandler excelOverDueOrderExcelService;
	@Resource
	private ExcelUpcomingOrderHandler excelUpcomingOrderService;
	@Resource
	private OrderService orderService;
	@Resource
	private FinancePaymentRecordService financePaymentRecordService;
	@Resource
	private AppArriveRecordService appArriveRecordService;
	@Resource
	private ReceiveOrderMapService receiveOrderMapService;
	@Resource
	private TransactionRecordLogService transactionRecordLogService;
	public static DateFormat sf;

	public void sendDailyReportForPartners(Long appId, Date report_date,
			String excelSubjectName, String companyName) throws IOException,
			ParseException {
		create_and_sent_daily_customer_report_via_email(appId, report_date,
				excelSubjectName, companyName);
	}

	public void create_and_sent_daily_customer_report_via_email(Long appId,
			Date report_date, String excelSubjectName, String companyName)
			throws IOException, ParseException {
		Map<String, Object> returnResult = create_excel_reports(appId,
				report_date, companyName);
		create_and_sent_report_via_email(report_date, excelSubjectName,
				returnResult);
		deleteExcel(returnResult);
	}

	public void create_and_sent_report_via_email(Date report_date,
			String excelSubjectName, Map<String, Object> returnResult) {
		this.mailSenderHandler.setSubject(create_email_subject(report_date,
				excelSubjectName));
		this.mailSenderHandler.sendTemplateWithFile(returnResult);
	}

	public Map<String, Object> create_excel_reports(Long appId,
			Date report_date, String companyName) throws IOException {
		Map<String, Object> returnResult = new HashMap<String, Object>();
		returnResult.putAll(create_daily_payment_excel(report_date, appId,
				companyName));
		returnResult.putAll(create_overdue_order_excel(report_date, appId,
				companyName));
		returnResult.putAll(create_to_expire_order_excel(report_date, appId,
				companyName));
		return returnResult;
	}

	private String create_email_subject(Date report_date,
			String excelSubjectName) {
		return DateUtils.format(report_date, "yyyy-MM-dd") + excelSubjectName;
	}

	private Map<String, Object> create_to_expire_order_excel(Date date,
			Long appId, String companyName) throws IOException {
		List<Order> futureOrderList = upcoming_payment_order(date, appId);
		List<ReportDataGenerator> upcomingOrderData = new ArrayList<ReportDataGenerator>();
		for (Order order : futureOrderList) {
			upcomingOrderData.add(order);
		}
		Map<String, Object> returnResult = new HashMap<String, Object>();
		BigDecimal futureMoney = calc_sum_future_money(date, futureOrderList);
		String filePath = "";
		if (CollectionUtils.isNotEmpty(futureOrderList)) {
			filePath = this.excelUpcomingOrderService.createWorkBook(
					upcomingOrderData, futureMoney,
					UpcomingReportTitles.values(), date, companyName);
		}
		returnResult.put("futureOrderList", futureOrderList);
		returnResult.put("futureMoney", futureMoney);
		returnResult.put("upcoming_excel_file_path", filePath);
		return returnResult;
	}

	private BigDecimal calc_sum_future_money(Date date,
			List<Order> futureOrderList) {
		BigDecimal futureMoney = BigDecimal.ZERO;
		for (Order order : futureOrderList) {
			futureMoney = futureMoney.add(order.getTotalRent());
			int overTimeDays = DateUtils.getIntervalDays(date,
					order.getDueDate()).size() - 1;
			order.setOverDueDays(overTimeDays);
		}
		return futureMoney;
	}

	public Map<String, Object> create_daily_payment_excel(Date date,
			Long appId, String companyName) throws IOException {
		List<FinancePaymentRecord> financePaymentRecords = query_decuct_money_by_date(
				date, appId);
		BigDecimal financeMoney = calc_sum_paymoney_by_date(financePaymentRecords);
		String file_path = "";
		if (CollectionUtils.isNotEmpty(financePaymentRecords)) {
			file_path = create_excel(financePaymentRecords, financeMoney, date,
					appId, companyName);
		}
		Map<String, Object> returnResult = new HashMap<String, Object>();
		returnResult.put("financePaymentRecords", financePaymentRecords);
		returnResult.put("financeMoney", financeMoney);
		returnResult.put("finance_excel_file_path", file_path);

		return returnResult;
	}

	private String create_excel(
			List<FinancePaymentRecord> financePaymentRecords,
			BigDecimal financeMoney, Date createDate, Long appId,
			String companyName) throws IOException {
		List<ReportDataGenerator> financePaymentRecordList = reset_customer_pay_in_time(financePaymentRecords, appId);
		return this.excelFinanceService.createWorkBook(
				financePaymentRecordList, financeMoney,
				FinanceReportTitles.values(), createDate, companyName);

	}

	public List<ReportDataGenerator> reset_customer_pay_in_time(
			List<FinancePaymentRecord> financePaymentRecords, Long appId) {
		List<ReportDataGenerator> financePaymentRecordList = new ArrayList<ReportDataGenerator>();
		for (FinancePaymentRecord financePaymentRecord : financePaymentRecords) {
			Filter filter = new Filter();
			filter.addEquals("transactionRecord.orderNo", financePaymentRecord
					.getOrder().getOrderNo());
			filter.addEquals("transactionRecord.transactionRecordStatus",
					TransactionRecordStatus.CONFIRMED);
			filter.addEquals("transactionRecord.app.id", financePaymentRecord
					.getOrder().getContract().getApp().getId());
			filter.addEquals("transactionRecordOperateStatus",
					TransactionRecordOperateStatus.PAY);
			List<TransactionRecordLog> transactionRecordLogs = this.transactionRecordLogService
					.list(TransactionRecordLog.class, filter);

			if (CollectionUtils.isNotEmpty(transactionRecordLogs)
					&& appId == 1L) {
				financePaymentRecord
						.setCustomerPaymentTime(transactionRecordLogs.get(0)
								.getModifiedTime());
			}
			financePaymentRecordList.add(financePaymentRecord);
		}
		return financePaymentRecordList;
	}

	public BigDecimal calc_sum_paymoney_by_date(
			List<FinancePaymentRecord> financePaymentRecords) {
		BigDecimal financeMoney = BigDecimal.ZERO;
		for (FinancePaymentRecord financePaymentRecord : financePaymentRecords) {
			ReceiveOrderMap receiveOrderMap = this.receiveOrderMapService
					.queryReceiveOrderMapByOrderAndDeducted(financePaymentRecord
							.getOrder());
			if (receiveOrderMap != null) {
				financePaymentRecord.setCustomerPaymentTime(receiveOrderMap
						.getAppArriveRecord().getTime());
			}
			financeMoney = financeMoney.add(financePaymentRecord.getPayMoney());
		}
		return financeMoney;
	}

	private Map<String, Object> create_overdue_order_excel(Date date,
			Long appId, String companyName) throws IOException {
		List<Order> overTimeOrderList = query_overDue_return_money_order_list(
				date, appId);
		List<ReportDataGenerator> overDueReportData = new ArrayList<ReportDataGenerator>();
		for (Order order : overTimeOrderList) {
			overDueReportData.add(order);
		}
		BigDecimal nowMoney = calc_sum_overDue_money(date, overTimeOrderList);
		String file_path = "";
		if (CollectionUtils.isNotEmpty(overTimeOrderList)) {
			file_path = this.excelOverDueOrderExcelService.createWorkBook(
					overDueReportData, nowMoney, OverDueReportTitles.values(),
					date, companyName);
		}
		Map<String, Object> returnResult = new HashMap<String, Object>();
		returnResult.put("nowMoney", nowMoney);
		returnResult.put("overTimeOrderList", overTimeOrderList);
		returnResult.put("overDue_excel_file_path", file_path);
		return returnResult;
	}

	private BigDecimal calc_sum_overDue_money(Date date,
			List<Order> overTimeOrderList) {
		BigDecimal nowMoney = BigDecimal.ZERO;
		for (Order order : overTimeOrderList) {
			nowMoney = nowMoney.add(order.getTotalRent());
			int overDueDays = DateUtils.getIntervalDays(order.getDueDate(),
					date).size() - 1;
			order.setOverDueDays(overDueDays);
		}
		return nowMoney;
	}

	public void deleteExcel(Map<String, Object> filePathsMap) {
		File file = new File(filePathsMap.get("finance_excel_file_path")
				.toString());
		file.delete();
		file = new File(filePathsMap.get("overDue_excel_file_path").toString());
		file.delete();
		file = new File(filePathsMap.get("upcoming_excel_file_path").toString());
		file.delete();
	}

	public List<Order> query_overDue_return_money_order_list(Date date,
			Long appId) {
		Filter filter = new Filter();
		filter.addEquals("orderStatus", OrderStatus.fromValue(0));
		filter.addEquals("contract.app.id", appId);
		Date endDate = DateUtils.addDays(date, 1);
		filter.addLessThan("dueDate", endDate);
		com.demo2do.core.persistence.support.Order orderByDueDate = new com.demo2do.core.persistence.support.Order();
		orderByDueDate.add("due_date", "ASC");
		List<Order> orderList = orderService.list(Order.class, filter,
				orderByDueDate);
		return orderList;
	}

	public List<FinancePaymentRecord> query_decuct_money_by_date(Date date,
			Long appId) {
		Filter filter = new Filter();
		Date nextDay = DateUtils.addDays(date, 1);
		filter.addGreaterThan("paymentTime", date);
		filter.addLessThan("paymentTime", nextDay);
		filter.addEquals("order.contract.app.id", appId);
		filter.addEquals("order.repaymentType", RepaymentType.Normal);
		com.demo2do.core.persistence.support.Order orderByPaymentTime = new com.demo2do.core.persistence.support.Order();
		orderByPaymentTime.add("payment_time", "ASC");
		return this.financePaymentRecordService.list(
				FinancePaymentRecord.class, filter, orderByPaymentTime);
	}

	public List<Order> upcoming_payment_order(Date nowDate, Long appId) {
		Filter filter = new Filter();
		Date sevenDate = DateUtils.addDays(nowDate, 7);
		filter.addLessThan("dueDate", sevenDate);
		filter.addGreaterThan("dueDate", nowDate);
		filter.addEquals("contract.app.id", appId);
		filter.addEquals("orderStatus", OrderStatus.fromValue(0));
		com.demo2do.core.persistence.support.Order orderByDueDate = new com.demo2do.core.persistence.support.Order();
		orderByDueDate.add("due_date", "ASC");
		List<Order> orderFutureList = orderService.list(Order.class, filter,
				orderByDueDate);
		return orderFutureList;
	}

}